#include <mpi.h>
#include "functions.hpp"
#include <time.h>
#include <fstream>
#include <iostream>
#include <stdlib.h>



class Usual;


using namespace std;
using namespace MPI;
using namespace Magick;
using namespace MagickCore;


void usage(const string& cmd){
	cerr << "Usage: " << cmd << " filename" << endl;
	cerr << endl;
	MPI::Finalize();
    exit(0);
}


void abort(const string& msg){
    cerr << "Une erreur est apparue avec le message: " << msg ;
    cerr << endl << endl;

    MPI::COMM_WORLD.Abort(-1);
}

unsigned long nextWord(const string& str, unsigned long p)
{
    while(p < str.length() && (str[p] == ' ' || str[p] == '\t'))
        ++ p;

    return p;
}


string getWord(const string& str, unsigned long& p)
{
    unsigned long begin = p;

    while(p < str.length() && str[p] != ' ' && str[p] != '\t')
        ++ p;

    return str.substr(begin, p - begin);
}

void rootFunction(Usual* usuel,const char* filename){

        usuel = new Usual(filename);

        double initTime;
        //double totalTimeW;

        while(usuel->is_next())
        {
            cout << *usuel;
            //usuel->pop_picture();

            Magick::Image lImage = usuel->pop_picture();

            ssize_t rows    = lImage.rows();
            ssize_t columns = lImage.columns();
            ssize_t fin_i   = rows - usuel->get_matrix_size(); //indic lignes (vertical)
            ssize_t fin_j   = columns - usuel->get_matrix_size(); //indic colonnes (horizontal)
            int middle = (usuel->get_matrix_size() - 1)/2;

            Geometry geom(fin_j+1, fin_i+1);
            Magick::Image res(geom, Color("white"));

            MagickCore::PixelPacket *pix_cache = lImage.getPixels(0,0, rows, columns);
            res.modifyImage();
            Pixels my_res_cache(res);

            MagickCore::PixelPacket *pix_res = my_res_cache.get(0,0,fin_j,fin_i);

//start process
            initTime = MPI::Wtime();


            for(ssize_t i =0; i< fin_i ;++i)
            {
                for(ssize_t j =0; j< fin_j ; ++j)
                {
                    Color col("white");
                    Quantum blue(0), red(0), green(0);
                    for(int y = 0; y<  usuel->get_matrix_size()-1 ; ++y)
                    {
                        for(int x = 0; x <  usuel->get_matrix_size()-1 ;++x)
                        {
                            Color act_col = lImage.pixelColor(j+y, i+x);
                            blue  += act_col.blueQuantum()  * usuel->get_matrix(x,y);
                            red   += act_col.redQuantum()   * usuel->get_matrix(x,y);
                            green += act_col.greenQuantum() * usuel->get_matrix(x,y);
                        }
                    }
                    col.redQuantum( red );
                    col.greenQuantum( green );
                    col.blueQuantum( blue);
                    *pix_res++=col;
                }
            }
            my_res_cache.sync();
//finish process
            double inter = MPI::Wtime() - initTime;

            usuel->addProcessTime(inter);

            cout << " Process Time Image = " << inter << endl;



            res.display();
            res.magick("png");

            initTime = MPI::Wtime();

            res.write(usuel->get_write_path()+usuel->next_picture_string()+".png");
            inter = MPI::Wtime() - initTime;
            usuel->addWriteTime(inter);
            cout << " Write Time Image = " << inter << endl;

            usuel->pop_picture_string();

            //
        }


        cout << "***TOTAL Read Time = " << usuel->getReadTime() << endl;
        cout << "***TOTAL Process Time = " << usuel->getProcessTime() << endl;
        cout << "***TOTAL Write Time = " << usuel->getWriteTime() << endl;
        cout << "***TOTAL Time = " << usuel->getTotalTime() << endl;

time_t tim=time(NULL);
             char *s=ctime(&tim);
             s[strlen(s)-1]=0;        // remove \n


        //cout << "\tTimeee!    " << current_time << endl;
        cout << "\tRoot proc has done its job: " << s <<*usuel << endl << endl;
}

void myGatherv(PixelPacket *sendArray, int sendcounts , Datatype mytype, PixelPacket *rcvArray, int *recvcount, int *disps){
        MPI::COMM_WORLD.Gatherv(sendArray, sendcounts, mytype, rcvArray, recvcount, disps, MPI::INT, 0);
}


